/*
 *  CESlider.cpp
 *  LID Library
 *
 *  Created by Alexander Trutchenko on 09/11/11.
 *  Copyright 2011 League of Independent Developers. All rights reserved.
 *
 */

#include "cocos2dx_extentions/controls/CESlider.h"
#include "cocos2dx_extentions/controls/CESliderDelegate.h"

#include "cocos2dx_extentions/utility/CECocos2dUtility.h"

using namespace cocos2d;

namespace cocosext {

/////////////////////////////////////////////////////
//
/** CESlider 
* Slider control. Returns it's values to registered delegates
*/
/////////////////////////////////////////////////////

bool CESlider::init()
{
    if (!CCLayer::init())
        return false;

	this->setIsTouchEnabled(false);
    this->setIsTouchEnabled(true);

    CCSize sz = _sprBackNormal->getContentSize(); 
    this->setContentSize(sz);

    //back
    CCPoint center(sz.width/2.f, sz.height/2.f);
    _sprBackNormal->setPosition(center);
	_sprBackNormal->setAnchorPoint(CCPoint(0.5f, 0.5f));
    this->addChild(_sprBackNormal);
    _sprBackDisabled->setPosition(center);
	_sprBackDisabled->setAnchorPoint(CCPoint(0.5f, 0.5f));
    this->addChild(_sprBackDisabled);
    _sprBackDisabled->setIsVisible(false);

    //btn
    _btnRail = CCNode::node();
    _btnRail->setAnchorPoint(CCPoint(0.5f, 0.5f));
    _btnRail->setPosition(CCPoint(sz.width/2.f, sz.height/2.f)); 
    this->addChild(_btnRail);
    
    _btn = CCNode::node();
    CCSize btnSz = _sprBtnNormal->getContentSize();
    _btn->setContentSize(btnSz);
    _btn->setAnchorPoint(CCPoint(0.5f, 0.5f));
    _btn->setPosition(CCPointZero);
    _btnRail->addChild(_btn);

    _sprBtnDisabled->setPosition(ccpMid(btnSz));
    _sprBtnDisabled->setAnchorPoint(CCPoint(0.5f, 0.5f));
    _btn->addChild(_sprBtnDisabled);
    _sprBtnDisabled->setIsVisible(false);

    _sprBtnNormal->setPosition(ccpMid(btnSz));
    _sprBtnNormal->setAnchorPoint(CCPoint(0.5f, 0.5f));
    _btn->addChild(_sprBtnNormal);

    return true;
}

//CCLayer delegate
void CESlider::registerWithTouchDispatcher(void)
{
    CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this,0,true);
}

//CCTouchDelegate interface
bool CESlider::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
    if (_currentTouch != NULL || !isNodeContainsTouch(*_btn, pTouch))
        return false;
    
    _currentTouch = pTouch;

    _startPoint = pTouch->locationInView(pTouch->view());
    _startPoint = CCDirector::sharedDirector()->convertToGL(_startPoint);
    _startPoint = _btn->getParent()->convertToNodeSpace(_startPoint);

    for (CESliderDelegates::const_iterator it = _delegates.begin(); it != _delegates.end(); ++it)
        (*it)->onSlideBegin(this);

    return true;
}
void CESlider::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
{
    if (_currentTouch != pTouch)
        return;

    CCPoint currentPoint = pTouch->locationInView(pTouch->view());
    currentPoint = CCDirector::sharedDirector()->convertToGL(currentPoint);
    currentPoint = _btn->getParent()->convertToNodeSpace(currentPoint);
    
    onChangeCoords(currentPoint);
}
void CESlider::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
    _currentTouch = NULL;
    for (CESliderDelegates::const_iterator it = _delegates.begin(); it != _delegates.end(); ++it)
        (*it)->onSlideEnd(this);
}
void CESlider::ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent)
{
    _currentTouch = NULL;
    for (CESliderDelegates::const_iterator it = _delegates.begin(); it != _delegates.end(); ++it)
        (*it)->onSlideCancelled(this);
}

/* Enable/disable slider */
void CESlider::setIsEnabled(bool enabled)
{
    if (enabled == isEnabled())
        return;

    _sprBackNormal->setIsVisible(enabled);
    _sprBackDisabled->setIsVisible(!enabled);

    _sprBtnNormal->setIsVisible(enabled);
    _sprBtnDisabled->setIsVisible(!enabled);

    this->setIsTouchEnabled(enabled);
}


/* Register/unregister delegates */
void CESlider::registerDelegate(CESliderDelegate* delegate, bool synchronize)
{
    _delegates.push_back(delegate);
	if (synchronize)
		delegate->onValueChange(this);
}
void CESlider::unregisterDelegate(CESliderDelegate* delegate)
{
    _delegates.remove(delegate);
}

void CESlider::updateDelegates()
{
    for (CESliderDelegates::const_iterator it = _delegates.begin(); it != _delegates.end(); ++it)
        (*it)->onValueChange(this);
}




/////////////////////////////////////////////////////
//
/** CEHorizontalSlider 
* Horizontal slider
*/
/////////////////////////////////////////////////////

/* Static constructor */
CEHorizontalSlider* CEHorizontalSlider::node(CCSprite* backNormal, 
                                            CCSprite* backDisabled, 
                                            CCSprite* btnNormal, 
                                            CCSprite* btnDisabled, 
                                            float margin,
                                            float initValue)
{
    CEHorizontalSlider *pRet = new CEHorizontalSlider(backNormal, backDisabled, btnNormal, btnDisabled);
    CCAssert(pRet != NULL, NULL);
    if (pRet->init(margin, initValue))
    {
        pRet->autorelease();
        return pRet;
    }
    else
    {
        CC_SAFE_DELETE(pRet)
        return NULL;
    }
}

bool CEHorizontalSlider::init(float margin, float initValue)
{
    if (!CESlider::init())
        return false;

    CCSize sz = this->getContentSize();
    _btnRail->setContentSize(CCSize(sz.width - 2.f*margin, 1.f));

    this->setValue(initValue);

    return true;
}

float CEHorizontalSlider::getValue() const
{
    return _btn->getPosition().x/_btnRail->getContentSize().width;
}

void CEHorizontalSlider::setValue(float value)
{
    _btn->setPosition(CCPoint(value*_btnRail->getContentSize().width, 0.f));
    updateDelegates();
}

void CEHorizontalSlider::onChangeCoords(const CCPoint& currentPoint)
{
    const CCPoint& btnPoint = _btn->getPosition();
    const CCSize& railSize = _btn->getParent()->getContentSize();
    if ((currentPoint.x < FLT_EPSILON && btnPoint.x < FLT_EPSILON) ||
        (currentPoint.x > (railSize.width - FLT_EPSILON) && btnPoint.x > (railSize.width - FLT_EPSILON)))
        return;
    if (currentPoint.x < FLT_EPSILON)
        _btn->setPosition(ccp(0.f, 0.f));
    else if (currentPoint.x > (railSize.width - FLT_EPSILON))
        _btn->setPosition(ccp(railSize.width, 0.f));
    else
        _btn->setPosition(ccp(currentPoint.x, 0.f));

    updateDelegates();
}

}; // end namespace cocosext

